#/usr/bin/env python
# -*- coding: utf-8 -*-


'''
Created on 2011-10-10

@author: zhongfeng
'''

## {{{ http://code.activestate.com/recipes/84317/ (r2)
from threading import Condition,Thread
import copy

class Future(object):

    def __init__(self,func,*param):
        # Constructor
        self.__done=0
        self.__result=None
        self.__status='working'
        self.__C=Condition()   # Notify on this Condition when result is ready

        # Run the actual function in a separate thread
        self.__T=Thread(target=self.wrapper,args=(func,param))
        self.__T.setName("FutureThread")
        self.__T.start()

    def __repr__(self):
        return '<Future at '+hex(id(self))+':'+self.__status+'>'

    def __call__(self):
        self.__C.acquire()
        while self.__done == 0:
            self.__C.wait()
        self.__C.release()
        # We deepcopy __result to prevent accidental tampering with it.
        a=copy.deepcopy(self.__result)
        return a

    def wrapper(self, func, param):
        # Run the actual function, and let us housekeep around it
        self.__C.acquire()
        try:
            self.__result=func(*param)
        except:
            self.__result="Exception raised within Future"
        self.__done = 1
        self.__status = self.__result
        self.__C.notify()
        self.__C.release()
## end of http://code.activestate.com/recipes/84317/ }}}


class Singleton(object):
    ''' python 风格的单例模式 '''
    def __new__(cls,*args,**kargs):
        if '_inst' not in vars(cls):
            cls._inst = super(Singleton,cls).__new__(cls, *args,**kargs)
        return cls._inst
    
from time import time
def profile(func):
    def log(*args,**kargs):
        start = time()
        ret = func(*args,**kargs)
        end = time()
        expire = end - start
        print func.__name__,expire
        return ret
    return log

def profile1(sec):
    def around(func):
        def log(*args,**kargs):
            start = time()
            ret = func(*args,**kargs)
            end = time()
            expire = end - start
            print func.__name__,expire
            return ret
        return log
    
    def after(func):
        def log(*args,**kargs):
            start = time()
            print func.__name__,start
            ret = func(*args,**kargs)
            return ret
        return log
    return {'around':around,'after':after}[sec] 

from copy import deepcopy
def keeper(func):
    defArgs = func.__defaults__
    def wrap(*args,**kargs):
        funcDef = deepcopy(defArgs)
        func.__defaults__ = funcDef
        return func(*args,**kargs)
    return wrap

import md5
def hash(key):
    m = md5.new()
    keyStr = str(key)
    m.update(keyStr)
    return long(m.hexdigest(), 16)

import bisect

class ConsistentHash(object):
    def __init__(self,nodes,numOfReplicas = 4,hashfunc = hash):
        self.hashfunc = hashfunc
        self.numOfReplicas = numOfReplicas
        self.ring = {}
        self.__sorted_key_list = []
        if nodes:
            for node in nodes:
                self.addNode(node)
    
    def addNode(self,node):
        for num in range(self.numOfReplicas):
            genKey = self.hashfunc('%s:%s' % (node,num))
            self.ring[genKey] = node
            bisect.insort(self.__sorted_key_list,genKey)
    
    def removeNode(self,node):
        for num in range(self.numOfReplicas):
            key = self.hashfunc('%s:%s' % (node,num))
            del self.ring[key]
            self.__sorted_key_list.remove(key)
    
    def getNode(self,obj):
        genKey = self.hashfunc(obj)
        nodeKey = self.__getNodeKey(genKey)
        if nodeKey != None:
            return self.ring[nodeKey]
    
    def __getNodeKey(self,key):
        if not self.ring:
            return None
        for nodeKey in self.__sorted_key_list:
            if key <= nodeKey:
                return nodeKey
        return self.__sorted_key_list[0]
        
    
        
    
@keeper
def test(l = [],t = 2):
    l.append('1')
    print l
    return t

memcache_servers = ['192.168.0.246:11212',
                    '192.168.0.247:11212',
                    '192.168.0.249:11212',
                    '192.168.0.250:11212']



if __name__ == '__main__':
    f = Future(test, *([1,2,3],3))
    print f()